package com.leyou.order.service.impl;

import com.github.wxpay.sdk.WXPayUtil;
import com.leyou.common.enums.LyExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.common.threadlocals.UserHolder;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.HttpClient;
import com.leyou.common.utils.IdWorker;
import com.leyou.item.client.ItemClient;
import com.leyou.item.dto.SkuDTO;
import com.leyou.order.dto.CartDTO;
import com.leyou.order.dto.OrderDTO;
import com.leyou.order.enums.OrderStatusEnum;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderLogisticsMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.pojo.Order;
import com.leyou.order.pojo.OrderDetail;
import com.leyou.order.pojo.OrderLogistics;
import com.leyou.order.service.OrderService;
import com.leyou.order.vo.OrderDetailVO;
import com.leyou.order.vo.OrderLogisticsVO;
import com.leyou.order.vo.OrderVO;
import com.leyou.user.client.UserClient;
import com.leyou.user.dto.AddressDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Service
@Transactional
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderDetailMapper detailMapper;

    @Autowired
    private OrderLogisticsMapper logisticsMapper;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private ItemClient itemClient;

    @Autowired
    private UserClient userClient;


    @Override
    public Long createOrder(OrderDTO orderDTO) {
        //1、保存tb_order
        Order order = new Order();
//        1、订单编号
        long orderId = idWorker.nextId();
        order.setOrderId(orderId);
//        2、用户id
        Long userId = UserHolder.getUser().getId();
        order.setUserId(userId);
//        3、订单金额相关数据，需要查询商品信息后逐个运算并累加获取
        List<CartDTO> carts = orderDTO.getCarts();
        //收集订单中商品id集合
        List<Long> skuIds = carts.stream().map(CartDTO::getSkuId).collect(Collectors.toList());
        List<SkuDTO> skuDTOList = itemClient.querySkuListByIds(skuIds);

        //收集转换carts为map  map的key:skuId  value:num
        Map<Long, Integer> skuMap = carts.stream().collect(Collectors.toMap(CartDTO::getSkuId, CartDTO::getNum));
        Long totalFee=0L;
        //orderDetail列表
        List<OrderDetail> detailList = new ArrayList<>();

        for (SkuDTO skuDTO : skuDTOList) {
            Long skuId = skuDTO.getId();
            totalFee+=skuDTO.getPrice()*skuMap.get(skuId);
            //2、保存tb_order_detail
            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setOrderId(orderId);
            orderDetail.setSkuId(skuId);
            orderDetail.setTitle(skuDTO.getTitle());
            orderDetail.setPrice(skuDTO.getPrice());
            orderDetail.setOwnSpec(skuDTO.getOwnSpec());
            orderDetail.setNum(skuMap.get(skuId));
            orderDetail.setImage(StringUtils.substringBefore(skuDTO.getImages(),","));
            detailList.add(orderDetail);
        }
        int count = detailMapper.insertDetailList(detailList);
        if (count!=detailList.size()) {
            throw new LyException(LyExceptionEnum.INSERT_OPERATION_FAIL);
        }

        //支付总金额
        order.setTotalFee(totalFee);
        //order.setActualFee(totalFee+"邮费"-"优惠");
       // order.setActualFee(totalFee+0L);
        order.setActualFee(1L);
        //邮费
        order.setPostFee(0L);
        //支付方式
        order.setPaymentType(orderDTO.getPaymentType());
//        4、订单状态数据
        order.setStatus(OrderStatusEnum.INIT.value());
//        5、写入数据库
        count = orderMapper.insertSelective(order);
        if (count!=1) {
            throw new LyException(LyExceptionEnum.INSERT_OPERATION_FAIL);
        }

        //3、保存tb_order_logistics
        AddressDTO addressDTO = userClient.queryAddressById(userId, orderDTO.getAddressId());
        OrderLogistics orderLogistics = BeanHelper.copyProperties(addressDTO, OrderLogistics.class);
        orderLogistics.setOrderId(orderId);
        count =logisticsMapper.insertSelective(orderLogistics);
        if (count!=1) {
            throw new LyException(LyExceptionEnum.INSERT_OPERATION_FAIL);
        }

        //扣减库存
        itemClient.updateStock(skuMap);


        return orderId;
    }

    @Override
    public OrderVO queryOrderById(Long id) {
        //tb_order
        Order order = orderMapper.selectByPrimaryKey(id);
        OrderVO orderVO = BeanHelper.copyProperties(order, OrderVO.class);

        //tb_order_detail
        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setOrderId(id);
        List<OrderDetail> orderDetails = detailMapper.select(orderDetail);
        List<OrderDetailVO> orderDetailVOS = BeanHelper.copyWithCollection(orderDetails, OrderDetailVO.class);
        orderVO.setDetailList(orderDetailVOS);

        //tb_order_logistics
        OrderLogistics orderLogistics = logisticsMapper.selectByPrimaryKey(id);
        OrderLogisticsVO orderLogisticsVO = BeanHelper.copyProperties(orderLogistics, OrderLogisticsVO.class);
        orderVO.setLogistics(orderLogisticsVO);
        return orderVO;
    }

    @Value("${ly.pay.wx.appID}")
    private String appid;//公众号id
    @Value("${ly.pay.wx.mchID}")
    private String partner;//商户号id
    @Value("${ly.pay.wx.key}")
    private String partnerkey;//商户秘钥
    @Value("${ly.pay.wx.notifyurl}")
    private String notifyurl;//回调地址

    @Override
    public String getPayUrl(Long id) {
        try {
            //查询订单获取支付金额
            Order order = orderMapper.selectByPrimaryKey(id);
            if(order==null){
                throw new LyException(LyExceptionEnum.ORDER_DETAIL_NOT_FOUND);
            }

            //1、准备微信支付平台接口中必填参数  Map
            Map<String,String> paramMap = new HashMap<>();
            paramMap.put("appid",appid);
            paramMap.put("mch_id",partner);
            paramMap.put("nonce_str", WXPayUtil.generateNonceStr());
            paramMap.put("body","乐优商城");
            paramMap.put("appid",appid);
            paramMap.put("out_trade_no",id.toString());
            paramMap.put("total_fee",order.getActualFee().toString());
            paramMap.put("spbill_create_ip","127.0.0.1");
            paramMap.put("notify_url",notifyurl);
            paramMap.put("trade_type","NATIVE");
            paramMap.put("product_id","1");
            //2、调用微信SDK中的工具类将Map参数转为xml格式
            String xmlParam = WXPayUtil.generateSignedXml(paramMap, partnerkey);
            //3、基于httpclient工具类调用微信支付平台统一下单接口
            HttpClient httpClient = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
            httpClient.setHttps(true);
            httpClient.setXmlParam(xmlParam);
            httpClient.post();
            
            //4、处理响应接口 将xml格式返回值转为map
            String xmlResult = httpClient.getContent();
            Map<String, String> resultMap = WXPayUtil.xmlToMap(xmlResult);
            return resultMap.get("code_url");
        } catch (Exception e) {
            e.printStackTrace();
            throw new LyException(LyExceptionEnum.INVALID_PARAM_ERROR);
        }
    }

    @Override
    public Integer queryPayStatus(Long id) {

        try {
            //1、准备微信支付平台接口中必填参数  Map
            Map<String,String> paramMap = new HashMap<>();
            paramMap.put("appid",appid);
            paramMap.put("mch_id",partner);
            paramMap.put("nonce_str", WXPayUtil.generateNonceStr());
            paramMap.put("out_trade_no", id.toString());
            //2、调用微信SDK中的工具类将Map参数转为xml格式
            String xmlParam = WXPayUtil.generateSignedXml(paramMap, partnerkey);
            //3、基于httpclient工具类调用微信支付平台统一下单接口
            HttpClient httpClient = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");
            httpClient.setHttps(true);
            httpClient.setXmlParam(xmlParam);
            httpClient.post();
            //4、处理响应接口 将xml格式返回值转为map
            String xmlResult = httpClient.getContent();
            Map<String, String> resultMap = WXPayUtil.xmlToMap(xmlResult);

            if ("SUCCESS".equals(resultMap.get("trade_state"))) {
                //如果支付成功，需要更新乐优商城支付状态为已支付，并更新支付时间
                Order order = new Order();
                order.setOrderId(id);
                order.setStatus(OrderStatusEnum.PAY_UP.value());
                order.setPayTime(new Date());
                orderMapper.updateByPrimaryKeySelective(order);
            }

            return "SUCCESS".equals(resultMap.get("trade_state"))?1:0;
        } catch (Exception e) {
            e.printStackTrace();
            throw new LyException(LyExceptionEnum.INVALID_PAY_STATUS);
        }


    }



    @Override
    public void closeOverdueOrders(Date deadline) {
        //1、查询需要清理的订单数据
        List<Long> orderIds = orderMapper.queryOverdueUnpaidOrder(deadline);
        if(CollectionUtils.isEmpty(orderIds)){
            log.info("【订单服务】没有需要清理的订单");
            return;
        }

        //2、更新查询结果中的订单状态 由未支付改为交易关闭
        Order record = new Order();
        record.setCloseTime(new Date());
        record.setStatus(OrderStatusEnum.CLOSED.value());
        // 更新订单的条件
        Example example = new Example(Order.class);
        example.createCriteria().andIn("orderId", orderIds);
        // 更新
        int count = orderMapper.updateByExampleSelective(record, example);
        log.info("【订单服务】定时关闭订单数量：{}", count);
        if (count != orderIds.size()) {
            throw new LyException(LyExceptionEnum.UPDATE_OPERATION_FAIL);
        }

        //3、获取清理订单详情中的商品id和数量
        Example detailExample = new Example(OrderDetail.class);
        detailExample.createCriteria().andIn("orderId", orderIds);
        // 查询订单对应的订单详情
        List<OrderDetail> orderDetails = detailMapper.selectByExample(detailExample);
        if (CollectionUtils.isEmpty(orderDetails)) {
            throw new LyException(LyExceptionEnum.ORDER_DETAIL_NOT_FOUND);
        }
        // 把以商品skuId为key，取出其中对应的库存数据，并叠加求和作为值
        Map<Long, Integer> skuMap = orderDetails.stream()
                .collect(Collectors.groupingBy(
                        OrderDetail::getSkuId,
                        Collectors.summingInt(OrderDetail::getNum)));

        //4、调用商品微服务，恢复库存
        itemClient.plusStock(skuMap);

    }
}
